skynet的启动 2014.11.05

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


你可能感兴趣的:(skynet的启动 2014.11.05)