S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

skynet的启动 2014.11.05

Posted on 2014-11-05 17:44 S.l.e!ep.¢% 阅读(693) 评论(0)  编辑 收藏 引用 所属分类: Skynet
bootstrap(..); 之前的代码没看懂

bootstrap()代码如下
static void
bootstrap(
struct skynet_context * logger, const char * cmdline) {
    
int sz = strlen(cmdline);
    
char name[sz+1];
    
char args[sz+1];
    sscanf(cmdline, 
"%s %s", name, args);
    
struct skynet_context *ctx = skynet_context_new(name, args);
    
if (ctx == NULL) {
        skynet_error(NULL, 
"Bootstrap error : %s\n", cmdline);
        skynet_context_dispatchall(logger);
        exit(
1);
    }
}

一开始以为 skynet_context_new() 只是malloc()之类的调用而已
后来再看看 skynet_context_new() 的源码

struct skynet_context * 
skynet_context_new(
const char * name, const char *param) {
    
struct skynet_module * mod = skynet_module_query(name);

    
if (mod == NULL)
        
return NULL;

    
void *inst = skynet_module_instance_create(mod);
    
if (inst == NULL)
        
return NULL;
    
struct skynet_context * ctx = skynet_malloc(sizeof(*ctx));
    CHECKCALLING_INIT(ctx)

    ctx
->mod = mod;
    ctx
->instance = inst;
    ctx
->ref = 2;
    ctx
->cb = NULL;
    ctx
->cb_ud = NULL;
    ctx
->session_id = 0;
    ctx
->logfile = NULL;

    ctx
->init = false;
    ctx
->endless = false;
    
// Should set to 0 first to avoid skynet_handle_retireall get an uninitialized handle
    ctx->handle = 0;    
    ctx
->handle = skynet_handle_register(ctx);
    
struct message_queue * queue = ctx->queue = skynet_mq_create(ctx->handle);
    
// init function maybe use ctx->handle, so it must init at last
    context_inc();

    CHECKCALLING_BEGIN(ctx)
    
int r = skynet_module_instance_init(mod, inst, ctx, param);
    CHECKCALLING_END(ctx)
    
if (r == 0) {
        
struct skynet_context * ret = skynet_context_release(ctx);
        
if (ret) {
            ctx
->init = true;
        }
        skynet_globalmq_push(queue);
        
if (ret) {
            skynet_error(ret, 
"LAUNCH %s %s", name, param ? param : "");
        }
        
return ret;
    } 
else {
        skynet_error(ctx, 
"FAILED launch %s", name);
        uint32_t handle 
= ctx->handle;
        skynet_context_release(ctx);
        skynet_handle_retire(handle);
        
struct drop_t d = { handle };
        skynet_mq_release(queue, drop_message, 
&d);
        
return NULL;
    }
}

大概是进行了模块的初始化,并为这个模块创建消息队列, 并放到全局的队列里(注:模块初始化时会将 param 传进去)

之后开启线程,进行消息处理
_start(config->thread);

用GDB调试,看下堆栈
#0  _init (l=0x2b98570163a0, ctx=0x2b98570540f0, args=0x2b9857099070 "bootstrap", sz=9) at service-src/service_snlua.c:71
#
1  0x00002b9857d02469 in _launch (context=0x2b98570540f0, ud=0x2b98570163a0, type=0, session=0, source=16777218, msg=0x2b9857099070, sz=9) at service-src/service_snlua.c:125
#
2  0x0000000000409546 in dispatch_message (ctx=0x2b98570540f0, msg=0x420030e0) at skynet-src/skynet_server.c:254
#
3  0x00000000004096c4 in skynet_context_message_dispatch (sm=0x2b9857016440, q=0x2b98570530c0, weight=-1) at skynet-src/skynet_server.c:308
#
4  0x000000000040a98f in _worker (p=0x7fff54a5f8d0) at skynet-src/skynet_start.c:128

为何会调用到 _launch? 回到前面
static void
bootstrap(
struct skynet_context * logger, const char * cmdline) {
    
int sz = strlen(cmdline);
    
char name[sz+1];
    
char args[sz+1];
    sscanf(cmdline, 
"%s %s", name, args);
    
struct skynet_context *ctx = skynet_context_new(name, args); // 这里传的参数分别为 snlua bootstrap
    if (ctx == NULL) {
        skynet_error(NULL, 
"Bootstrap error : %s\n", cmdline);
        skynet_context_dispatchall(logger);
        exit(
1);
    }
}

调用的流程是这样的
#0  _open_sym (mod=0x2b9e0a032438) at skynet-src/skynet_module.c:76
#1  0x0000000000408463 in skynet_module_query (name=0x7fffa16ae600 "snlua") at skynet-src/skynet_module.c:107
#2  0x0000000000409099 in skynet_context_new (name=0x7fffa16ae600 "snlua", param=0x7fffa16ae5e0 "bootstrap") at skynet-src/skynet_server.c:117
#3  0x000000000040adda in bootstrap (logger=0x2b9e0a054080, cmdline=0x2b9e0a0aa298 "snlua bootstrap") at skynet-src/skynet_start.c:204
#4  0x000000000040aedb in skynet_start (config=0x7fffa16ae6d0) at skynet-src/skynet_start.c:232
#5  0x000000000040751e in main (argc=2, argv=0x7fffa16ae7f8) at skynet-src/skynet_main.c:139

skynet_context_new 会先去 cservice目录下 查找 snlua.so , 然后分别找
snlua_create  --->  skynet_module->create
snlua_init    --->  skynet_module->init
snlua_release --->  skynet_module->release
这三个函数然后分别赋值给
skynet_module 的 create / init / release

snlua.so 的代码在 service_snlua.c
看 snlua_init() 函数代码就知道它将 skynet_context 的 cb 赋值为
_launch

int
snlua_init(
struct snlua *l, struct skynet_context *ctx, const char * args) {
    
int sz = strlen(args);
    
char * tmp = skynet_malloc(sz);
    memcpy(tmp, args, sz);
    skynet_callback(ctx, l , _launch);  // 这句代码将
skynet_context 的 cb 赋值为 _launch
   
const char * self = skynet_command(ctx, "REG", NULL);
    uint32_t handle_id 
= strtoul(self+1, NULL, 16);
    
// it must be first message
    skynet_send(ctx, 0, handle_id, PTYPE_TAG_DONTCOPY,0, tmp, sz);
    
return 0;
}


再看回下面的消息分派 dispatch_message() 里有以下代码, 实际上就是调用了 _launch()
    if (!ctx->cb(ctx, ctx->cb_ud, type, msg->session, msg->source, msg->data, sz)) {
        skynet_free(msg->data);
    }

#0  _init (l=0x2b98570163a0, ctx=0x2b98570540f0, args=0x2b9857099070 "bootstrap", sz=9) at service-src/service_snlua.c:71
#
1  0x00002b9857d02469 in _launch (context=0x2b98570540f0, ud=0x2b98570163a0, type=0, session=0, source=16777218, msg=0x2b9857099070, sz=9) at service-src/service_snlua.c:125
#
2  0x0000000000409546 in dispatch_message (ctx=0x2b98570540f0, msg=0x420030e0) at skynet-src/skynet_server.c:254
#
3  0x00000000004096c4 in skynet_context_message_dispatch (sm=0x2b9857016440, q=0x2b98570530c0, weight=-1) at skynet-src/skynet_server.c:308
#
4  0x000000000040a98f in _worker (p=0x7fff54a5f8d0) at skynet-src/skynet_start.c:128



只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理