- 创建新的 userdata
- 创建一个新 thread 对象,把 callback function 至于这个 thread 中
- 把新 thread 绑定 userdata 的 uservalue 上(防止 gc)
- userdata 的 C 指针放到 C 端,用于 callback 调用
- callback function 放到新 thead 中而不是注册表中是因为这样做比从注册表中读会 callback function 要高效
122 static int
123 lcallback(lua_State *L) {
124 > struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
125 > int forward = lua_toboolean(L, 2); // 获取第二个参数
126 > luaL_checktype(L,1,LUA_TFUNCTION); // 检查第一个参数是否是 lua function
127 > lua_settop(L,1); // 弹出除第一个参数外的所有参数,即 lua function 在 L 的栈底
128 > struct callback_context * cb_ctx = (struct callback_context *)lua_newuserdatauv(L, sizeof(*cb_ctx), 2); // 创建 userdata callback_context 并压入到 L 的栈中
129 > cb_ctx->L = lua_newthread(L); // 创建一个新线程并压入 L 的栈中
130 > lua_pushcfunction(cb_ctx->L, traceback); // 将 c 函数 traceback 压入新线程的栈中
131 > lua_setiuservalue(L, -2, 1); // 将新线程弹出并设置为 128 创建的 userdata 的 uservalue
132 > lua_getfield(L, LUA_REGISTRYINDEX, "callback_context"); // 将注册表下标为 "callback_context" 的值压入 L 的栈中
133 > lua_setiuservalue(L, -2, 2); // 将上面压入的值设置为 128 创建的 userdata 的 uservalue
134 > lua_setfield(L, LUA_REGISTRYINDEX, "callback_context"); // 将 128 创建的 userdata 设置为注册表下标为 "callback_context" 的值
135 > lua_xmove(L, cb_ctx->L, 1); // 将 userdata 从 L 中弹出并压入新线程中
136
137 > skynet_callback(context, cb_ctx, (forward)?(_forward_pre):(_cb_pre)); // 将 _cb_pre/_forward_pre 设置为 context 的 callback,两种区别为是否自动释放 skynet msg 的空间
138 > return 0;
139 }