skynet_server是skynetc层的核心。代码主要实现skynet.h和skynet_server.h的api函数。
skynet.h主要提供了消息发送,消息回调函数注册等等。
void skynet_error(struct skynet_context * context, const char *msg, ...);
const char * skynet_command(struct skynet_context * context, const char * cmd , const char * parm);
uint32_t skynet_queryname(struct skynet_context * context, const char * name);
int skynet_send(struct skynet_context * context, uint32_t source, uint32_t destination , int type, int session, void * msg, size_t sz);
int skynet_sendname(struct skynet_context * context, uint32_t source, const char * destination , int type, int session, void * msg, size_t sz);
int skynet_isremote(struct skynet_context *, uint32_t handle, int * harbor);
typedef int (*skynet_cb)(struct skynet_context * context, void *ud, int type, int session, uint32_t source , const void * msg, size_t sz);
void skynet_callback(struct skynet_context * context, void *ud, skynet_cb cb);
uint32_t skynet_current_handle(void);
uint64_t skynet_now(void);
void skynet_debug_memory(const char *info); // for debug use, output current service memory to stderr
skynet_server.h主要提供了对context的一系列操作,比如创建,销毁等待。
struct skynet_context * skynet_context_new(const char * name, const char * parm);
void skynet_context_grab(struct skynet_context *);
void skynet_context_reserve(struct skynet_context *ctx);
struct skynet_context * skynet_context_release(struct skynet_context *);
uint32_t skynet_context_handle(struct skynet_context *);
int skynet_context_push(uint32_t handle, struct skynet_message *message);
void skynet_context_send(struct skynet_context * context, void * msg, size_t sz, uint32_t source, int type, int session);
int skynet_context_newsession(struct skynet_context *);
struct message_queue * skynet_context_message_dispatch(struct skynet_monitor *, struct message_queue *, int weight); // return next queue
int skynet_context_total();
void skynet_context_dispatchall(struct skynet_context * context); // for skynet_error output before exit
void skynet_context_endless(uint32_t handle); // for monitor
void skynet_globalinit(void);
void skynet_globalexit(void);
void skynet_initthread(int m);
void skynet_profile_enable(int enable);
struct skynet_context {
void * instance; //c_moudle _create函数返回的实例指针
struct skynet_module * mod; //c_moudle 的指针,方便调用模块,create,init,signal,release接口
void * cb_ud; //skynet_call_back设置的回调函数数据指针
skynet_cb cb; //skynet_call_back设置的回调函数指针
struct message_queue *queue; //消息队列
ATOM_POINTER logfile; //日志文件
uint64_t cpu_cost; // in microsec
uint64_t cpu_start; // in microsec
char result[32]; //执行cmd函数的结果
uint32_t handle; //context句柄唯一id
int session_id; //消息session_id用于对应消息回复
ATOM_INT ref; //引用计数,当引用计数为0时,可以释放context内存
int message_count; //统计消息处理总数
bool init; //是否初始化
bool endless; //是否出现单个消息处理太久
bool profile; //是否需要统计消息处理cpu占用时间
CHECKCALLING_DECL //自旋锁
};
struct skynet_context *
skynet_context_new(const char * name, const char *param) {
struct skynet_module * mod = skynet_module_query(name); //查询加载c服务动态库
if (mod == NULL)
return NULL;
void *inst = skynet_module_instance_create(mod); //调用c服务创建函数接口
if (inst == NULL)
return NULL;
struct skynet_context * ctx = skynet_malloc(sizeof(*ctx));
CHECKCALLING_INIT(ctx)
ctx->mod = mod;
ctx->instance = inst;
ATOM_INIT(&ctx->ref , 2);
ctx->cb = NULL;
ctx->cb_ud = NULL;
ctx->session_id = 0;
ATOM_INIT(&ctx->logfile, (uintptr_t)NULL);
ctx->init = false;
ctx->endless = false;
ctx->cpu_cost = 0;
ctx->cpu_start = 0;
ctx->message_count = 0;
ctx->profile = G_NODE.profile;
// 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); //调用c服务init接口,通常init函数会设置好回调函数
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;
}
}
command接口包装了一系列命令
static struct command_func cmd_funcs[] = {
{ "TIMEOUT", cmd_timeout }, //注册定时器任务
{ "REG", cmd_reg } //设置别名
{ "QUERY", cmd_query }, //通过别名查询handle_id
{ "NAME", cmd_name }, //设置handle_id的别名
{ "EXIT", cmd_exit }, //安全退出
{ "KILL", cmd_kill }, //强制杀掉一个服务
{ "LAUNCH", cmd_launch }, //拉起一个服务
{ "GETENV", cmd_getenv }, //获取环境变量
{ "SETENV", cmd_setenv }, //设置环境变量
{ "STARTTIME", cmd_starttime }, //进程开始时间戳
{ "ABORT", cmd_abort }, //退出进程
{ "MONITOR", cmd_monitor }, //设置监控退出服务id
{ "STAT", cmd_stat }, //提供获取 mqlen,endless,cpu,message命令
{ "LOGON", cmd_logon }, //消息日志打开
{ "LOGOFF", cmd_logoff }, //消息日志关闭
{ "SIGNAL", cmd_signal }, //调用moudle的signal处理函数
{ NULL, NULL },
};
const char *
skynet_command(struct skynet_context * context, const char * cmd , const char * param) {
struct command_func * method = &cmd_funcs[0];
while(method->name) {
if (strcmp(cmd, method->name) == 0) {
return method->func(context, param);
}
++method;
}
return NULL;
}
skynet对消息处理不是说有多少消息就一次性处理完了,每个线程都会安排一个权重weight
当weight大于0的时候,n会取到 len / 2^weight,一次会处理掉n条消息,这样就保证了消息量大的服务不会处理不过来。
当权重为-1,该线程每次只处理一条消息,确保其他服务消息有人处理。
struct message_queue *
skynet_context_message_dispatch(struct skynet_monitor *sm, struct message_queue *q, int weight) {
if (q == NULL) {
q = skynet_globalmq_pop();
if (q==NULL)
return NULL;
}
uint32_t handle = skynet_mq_handle(q);
struct skynet_context * ctx = skynet_handle_grab(handle);
if (ctx == NULL) {
struct drop_t d = { handle };
skynet_mq_release(q, drop_message, &d);
return skynet_globalmq_pop();
}
int i,n=1;
struct skynet_message msg;
for (i=0;i= 0) {
n = skynet_mq_length(q);
n >>= weight;
}
int overload = skynet_mq_overload(q);
if (overload) {
skynet_error(ctx, "May overload, message queue length = %d", overload);
}
skynet_monitor_trigger(sm, msg.source , handle);
if (ctx->cb == NULL) {
skynet_free(msg.data);
} else {
dispatch_message(ctx, &msg);
}
skynet_monitor_trigger(sm, 0,0);
}
assert(q == ctx->queue);
struct message_queue *nq = skynet_globalmq_pop();
if (nq) {
// If global mq is not empty , push q back, and return next queue (nq)
// Else (global mq is empty or block, don't push q back, and return q again (for next dispatch)
skynet_globalmq_push(q);
q = nq;
}
skynet_context_release(ctx);
return q;
}
static int weight[] = {
-1, -1, -1, -1, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, };
weight是对应的线程的权重,当有8个线程时,线程的权重为-1,-1,-1,-1,0,0,0,0。
当权重为0,该线线程会处理全部消息,n = len >> weight = len / 2^weight
当权重为1,该线线程会一半消息,n = len >> weight = len / 2^weight
当权重为2,该线线程会4分之一消息,n = len >> weight = len / 2^weight
当权重为3,该线线程会8分之一消息,n = len >> weight = len / 2^weight
可见这样设计兼顾了深度和广度。