Blame view

docs/启动服务流程分析.txt 2.67 KB
314bc5df   zhengshouren   提交服务器初始代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  function skynet.launch(...)
  	c.command("LAUNCH", table.concat({...}, " "))
  	......
  end
  
  lua-skynet.c | _command | skynet_command
  skynet_server.c | cmd_launch | skynet_context_new
  
  ====================================================================
  
  function skynet.newservice(name, ...)
  	return skynet.call(".launcher", "lua" , "LAUNCH", "snlua", name, ...)
  end
  
  service/launcher.lua
  
  返回 "RESPONSE", skynet.pack
  
  newservice 收到 "RESPONSE"
  
  launch 服务就有所有服务的地址
  
  可以统计所有服务,gc某个服务,stats某个服务
  
  ====================================================================
  
  再来看 skynet_context_new
  
  1. 获取 skynet_module
  struct skynet_module {
  	const char * name; 模块名
  	void * module; 模块对应的动态库(snlua, 或者其他动态库)
  	skynet_dl_create create; 创建函数
  	skynet_dl_init init; 初始化函数
  	skynet_dl_release release; 释放函数
  	skynet_dl_signal signal; 信号函数
  };
  
  2. 调用 M->create() 函数
  创建 lua vm
  struct snlua {
  	lua_State * L;
  	struct skynet_context * ctx;
  };
  构建 snlua 结构
  
  3. 创建并初始化 上下文
  struct skynet_context {
  	void * instance; snlua结构
  	struct skynet_module * mod;
  	void * cb_ud;
  	skynet_cb cb; callback函数指针
  	struct message_queue *queue; 消息队列
  	FILE * logfile; 日志输出文件
  	char result[32];
  	uint32_t handle;
  	int session_id;
  	int ref;
  	bool init;
  	bool endless;
  	CHECKCALLING_DECL
  };
  创建消息队列
  
  4. 调用 M->init()函数
  设置回调函数
  skynet_callback(ctx, l , _launch);
  ctx->cb 回调函数 _launch
  ctx->cb_ud snlua结构
  
  "REG" 注册
  发送第一个消息
  skynet_send(ctx, 0, handle_id, PTYPE_TAG_DONTCOPY, 0, tmp, sz);
  
  调用 _launch 函数
  skynet_callback(context, NULL, NULL);
  将回调函数清空
  接着调用 _init 函数
  
  将 skynet_context 的指针地址 存入 lua 环境中 (通过轻量用户数据来实现)
  加载常用库
  将 LUA_PATH LUA_CPATH LUA_SERVICE LUA_PRELOAD 写入全局table中
  通过 loader.lua 加载所有的lua库
  
  5. 将次级消息队列压入全局消息队列
  skynet_globalmq_push
  
  6. 在服务主模块中调用
  skynet.start 设置回调函数
  c.callback 将 _cb作为键,值lua 回调函数 写入lua环境中
  skynet_callback
  
  lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
  lua_State *gL = lua_tothread(L,-1);
  
  cb_ud 保存 主线程,主线程不会被回收,生命周期同vm
  
  主线程 栈上永远保存着两个值
  traceback
  回调函数
  
  调用 回调函数
  r = lua_pcall(L, 5, 0, 1);
  栈上第一个函数作为 错误处理函数
  
  主线程 调用回调函数 回调函数分配线程去处理 每条消息
  
  7. 错误处理
  在 发生错误的 服务 处理
  
  回调函数发生在主线程