struct skynet_monitor {
ATOM_INT version;
int check_version;
uint32_t source;
uint32_t destination;
};
- skynet 的每个工作线程对应一个 skynet_monitor 结构体
- version:当前的版本号
- check_version:检查版本号
- source:发送消息的 actor 地址
- destination:接收消息的 actor 地址
void skynet_monitor_check(struct skynet_monitor *sm) {
if (sm->version == sm->check_version) {
if (sm->destination) {
skynet_context_endless(sm->destination);
skynet_error(NULL, "A message from [ :%08x ] to [ :%08x ] maybe in an endless loop (version = %d)", sm->source , sm->destination, sm->version);
}
} else {
sm->check_version = sm->version;
}
}
- monitor 线程每 5s 执行 skynet_monitor_check 函数,如果发现 destination ,则表示该 actor 可能陷入死循环中,这里只把该 actor 标记为死循环状态
struct message_queue *skynet_context_message_dispatch(struct skynet_monitor *sm, struct message_queue *q, int weight) {
...
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);
...
}
skynet_monitor_trigger(struct skynet_monitor *sm, uint32_t source, uint32_t destination) {
sm->source = source;
sm->destination = destination;
ATOM_FINC(&sm->version);
}
- 在调用 dispatch_message 处理 actor 的消息的前会调用 skynet_monitor_trigger 把该线程对应 skynet_monitor 的 destination 字段设置为目标 actor 的地址
- 在调用 dispatch_message 处理 actor 的消息的后会调用 skynet_monitor_trigger 把该线程对应 skynet_monitor 的 destination 字段设置为无效
- 每个线程都有一个 skynet_monitor 结构体用于记录监控信息
- 工作线程执行消息处理前调用 skynet_monitor_trigger 把 skynet_monitor 的 destination 字段设置为处理函数所在 actor 的地址
- 工作线程执行消息处理后调用 skynet_monitor_trigger 把 skynet_monitor 的 destination 字段设置为无效
- monitor 线程每 5s 都会检查每个线程的 skynet_monitor 的 destination 字段是否有效,有效表示该 actor 对象的处理函数可能陷入死循环
- monitor 线程检测到可能陷入死循环的 actor 只是把该 actor 标记为 endless 并打印错误