|
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
|